package NoP2P;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;

import Server.GlobaisServidor;

public class ClienteNoP2P{
	private static String localNo;
	private static String host;
	private static String arquivo;
	protected static long inicioMovimentacao;

	public static void main(String[] args) {
		Scanner leitor = new Scanner(System.in);
		(new RequisicaoMovimento()).start();
		boolean naoSaiu = true;
		 
		while(naoSaiu){
			System.out.println("O que voce deseja fazer?");
			System.out.println("1. Criar arquivo de teste");
			System.out.println("2. Compartilhar arquivo");
			System.out.println("3. Ler arquivo");
			System.out.println("4. Remover arquivo");
			System.out.println("5. Mover arquivo");
			System.out.println("6. Sair");
			int opcao = leitor.nextInt();
			leitor.nextLine();
			localNo = args[0];
			host = "frontend";
			boolean sucesso = false;
			
			switch (opcao){
				case 1:
					Arquivo.criarArquivoTeste(localNo);
					break;
				case 2:
					System.out.println("Digite o nome do arquivo a ser compartilhado: ");
					String nomeArquivo = leitor.nextLine();
					long tempInicial = System.currentTimeMillis(); 
					sucesso = enviarInfoServidor( GlobaisServidor.CRIAR_ARQUIVO,nomeArquivo, localNo, "");
					long tempFinal = System.currentTimeMillis(); 
					Arquivo.gerarLogTemporal("Registro de arquivo compartilhado",
							tempFinal-tempInicial, null);
					if(!sucesso) System.out.println("Problema ao compartilhar arquivo ");
					break;
				case 3:
					System.out.println("Digite o nome do arquivo a ser lido: ");
					nomeArquivo = leitor.nextLine();
					tempInicial = System.currentTimeMillis();
					sucesso = enviarInfoServidor( GlobaisServidor.LER_ARQUIVO,nomeArquivo, localNo, "");
					tempFinal = System.currentTimeMillis();
					long tamanho = (new File(nomeArquivo)).length();
					Arquivo.gerarLogTemporal("Leitura de arquivo remoto", 
							tempFinal-tempInicial, tamanho);
					if(!sucesso) System.out.println("Problema ao ler arquivo ");
					break;
				case 4:
					System.out.println("Digite o nome do arquivo a ser removido: ");
					nomeArquivo = leitor.nextLine();
					tempInicial = System.currentTimeMillis();
					sucesso = enviarInfoServidor( GlobaisServidor.LER_ARQUIVO,nomeArquivo, localNo, "");
					if(sucesso){
						File arq = new File( nomeArquivo);
						arq.delete();
					}
					else{
						System.out.println("Problema ao remover arquivo ");
					}
					tempFinal = System.currentTimeMillis();
					Arquivo.gerarLogTemporal("Remocao de arquivo",
							tempFinal-tempInicial, null);
					break;
				case 5:
					System.out.println("Digite o nome do arquivo a ser movido: ");
					nomeArquivo = leitor.nextLine();
					System.out.println("Digite o servidor de origem: ");
					String nomeOrigem = leitor.nextLine();
					System.out.println("Digite o servidor de destino: ");
					String nomeDestino = leitor.nextLine();
					inicioMovimentacao = System.currentTimeMillis();
					sucesso = enviarInfoServidor(GlobaisServidor.MOVER_ARQUIVO,
							nomeArquivo, nomeOrigem, nomeDestino);
					if(!sucesso)System.out.println("Problema ao mover arquivo ");
					break;
				case 6:
					naoSaiu = false;
					System.exit(0);
					break;
				default:
					System.out.println("Opcao Invalida");
					break;
			}
		}

	}
	private static boolean enviarInfoServidor(int comando, String param1, String param2, String param3){
		int port = 19888; 
		StringBuffer instr = new StringBuffer();
		try {
		      /** Obtain an address object of the server */
		      InetAddress address = InetAddress.getByName(host);
		      /** Establish a socket connetion */
		      Socket connection = new Socket(address, port);
		      /** Instantiate a BufferedOutputStream object */
		      BufferedOutputStream bos = new BufferedOutputStream(connection.
		              getOutputStream());

		      /** Instantiate an OutputStreamWriter object with the optional character
		      * encoding.
		      */
		      OutputStreamWriter osw = new OutputStreamWriter(bos, "US-ASCII");
		      String process = (char)comando + param1 + "/" + param2 + "/" + param3 + "/";
		      /** Write across the socket connection and flush the buffer */
		      osw.write(process);
		      osw.flush();
		      
		      if(comando == GlobaisServidor.CRIAR_ARQUIVO){
		    	  connection.close();
		    	  return true;
		      }
		      
		      BufferedInputStream bis = new BufferedInputStream(connection.
		              getInputStream());
		      InputStreamReader isr = new InputStreamReader(bis, "US-ASCII");
		      int c;
		      while ( (c = isr.read()) != '\0')
		    	  instr.append( (char) c);
		          /**Instantiate an InputStreamReader with the optional
		           * character encoding.
		           */
		     connection.close();
		     if(comando == GlobaisServidor.LER_ARQUIVO){
		    	 connection.close();
		    	  return lerServidores(instr.toString(), param1);
		      }
		     return Boolean.parseBoolean(instr.toString());
		}
	    catch (IOException f) {
	      f.printStackTrace();
	    }
	    catch (Exception g) {
	      g.printStackTrace();
	    }
		finally{
			
		}
		
		return false;
		          
	}
	private static boolean lerServidores (String resposta, String nomeArquivo){
		if(resposta == null || resposta.equals("")) return false;
		String[] servidores = resposta.split("/");
		System.out.println(resposta);
		for(String servidor : servidores){
			if(servidor.equals(localNo)){
				arquivo = Arquivo.lerLocal(nomeArquivo);
				System.out.print(arquivo);
				System.out.println("");
				return true;
			}
		}
		return lerArquivoDeServidor(servidores[0], nomeArquivo);
	}
	protected static boolean lerArquivoDeServidor(String servidor,String nomeArquivo){
		int port = 19886;
		 Socket sockServer = null;
	     FileOutputStream fos = null;
	     ObjectInputStream is = null;
	 
	        try {
	        	// Criando conexão com o servidor
	            sockServer = new Socket(InetAddress.getByName(servidor), port);
	        	/** Instantiate a BufferedOutputStream object */
			      BufferedOutputStream bos = new BufferedOutputStream(sockServer.
			              getOutputStream());

			      /** Instantiate an OutputStreamWriter object with the optional character
			      * encoding.
			      */
			      OutputStreamWriter osw = new OutputStreamWriter(bos, "US-ASCII");
			      String process = nomeArquivo + "/";
			      /** Write across the socket connection and flush the buffer */
			      osw.write(process);
			      osw.flush();
	            
	            is = new ObjectInputStream(sockServer.getInputStream());
	 
	            // Cria arquivo local no cliente
	            fos = new FileOutputStream(new File( nomeArquivo));
	            
	            // Prepara variaveis para transferencia
	            byte[] cbuffer = new byte[4096];
	 
	            // Copia conteudo do canal
	            while(true){
	            	int len = is.read(cbuffer);
	            	if(len == -1) break;
	            	fos.write(cbuffer, 0, len);
	            }
	             
	        } catch (Exception e) {
	            e.printStackTrace();
	        } finally {
	            if (sockServer != null) {
	                try {
	                    sockServer.close();
	                } catch (IOException e1) {
	                    e1.printStackTrace();
	                }
	            }
	 
	            if (fos != null) {
	                try {
	                    fos.close();
	                } catch (IOException e1) {
	                    e1.printStackTrace();
	                }
	            }
	 
	            if (is != null) {
	                try {
	                    is.close();
	                } catch (IOException e1) {
	                    e1.printStackTrace();
	                }
	            }
	        } 
	        return true;
	}
}
